package com.lhn.locks;

import org.junit.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 线程阻塞与通知
 *
 * @author lhn
 * @date 2022/09/04 10:18
 * @since 1.0.0
 **/
public class LockSupportDemo {

    static final Object syncWaitNotify = new Object();

    @Test
    public void SyncWaitNotify() {
        final Object syncWaitNotify = new Object();
        new Thread(() -> {
            synchronized (syncWaitNotify) {
                try {
                    System.out.println(Thread.currentThread().getName() + " 睡眠！");
                    try {
                        TimeUnit.SECONDS.sleep(1L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    syncWaitNotify.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName() + " 苏醒！");
            }
        }, "t1").start();

        //暂停几秒钟线程
        try {
            TimeUnit.SECONDS.sleep(1L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            synchronized (syncWaitNotify) {
                syncWaitNotify.notify();
                System.out.println(Thread.currentThread().getName() + " 发起通知！");
            }
        }, "t2").start();
    }

    @Test
    public void SyncWaitNotifyExc1() {
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " 睡眠！");
                syncWaitNotify.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + " 苏醒！");
        }, "t1").start();

        //暂停几秒钟线程
        try {
            TimeUnit.SECONDS.sleep(3L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            syncWaitNotify.notify();
            System.out.println(Thread.currentThread().getName() + " 发起通知！");
        }, "t2").start();
    }

    @Test
    public void SyncWaitNotifyExc2() {
        new Thread(() -> {
            synchronized (syncWaitNotify) {
                syncWaitNotify.notify();
                System.out.println(Thread.currentThread().getName() + " 发起通知！");
            }
        }, "t2").start();

        //暂停几秒钟线程
        try {
            TimeUnit.SECONDS.sleep(3L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            try {
                synchronized (syncWaitNotify) {
                    System.out.println(Thread.currentThread().getName() + " 睡眠！");
                    syncWaitNotify.wait();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + " 苏醒！");
        }, "t1").start();
    }

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    @Test
    public void ConditionAwaitSignal() {
        new Thread(() -> {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + " 睡眠！");
                condition.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
            System.out.println(Thread.currentThread().getName() + " 苏醒！");
        }, "t1").start();

        try {
            TimeUnit.SECONDS.sleep(3L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            try {
                lock.lock();
                condition.signal();
                System.out.println(Thread.currentThread().getName() + " 发起通知！");
            } finally {
                lock.unlock();
            }
        }, "t2").start();
    }

    @Test
    public void ConditionAwaitSignalExc1() {
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " 睡眠！");
                condition.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + " 苏醒！");
        }, "t1").start();

        try {
            TimeUnit.SECONDS.sleep(3L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            condition.signal();
            System.out.println(Thread.currentThread().getName() + " 发起通知！");
        }, "t2").start();
    }

    @Test
    public void ConditionAwaitSignalExc2() {
        new Thread(() -> {
            try {
                lock.lock();
                condition.signal();
                System.out.println(Thread.currentThread().getName() + " 发起通知！");
            } finally {
                lock.unlock();
            }
        }, "t2").start();

        try {
            TimeUnit.SECONDS.sleep(3L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + " 睡眠！");
                condition.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
            System.out.println(Thread.currentThread().getName() + " 苏醒！");
        }, "t1").start();
    }

    @Test
    public void LockSupportPackUnPack() {
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " 睡眠！");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + " 苏醒！");
        }, "t1");
        t1.start();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            LockSupport.unpark(t1);
            System.out.println(Thread.currentThread().getName() + " 发起通知！");
        }, "t2").start();
    }

    @Test
    public void LockSupportUnPackPack() {
        Thread t1 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 睡眠！");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + " 苏醒！");
        }, "t1");
        new Thread(() -> {
            LockSupport.unpark(t1);
            System.out.println(Thread.currentThread().getName() + " 发起通知！");
        }, "t2").start();
        t1.start();
    }


    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 睡眠！");
            LockSupport.park();
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + " 苏醒！");
        }, "t1");
        new Thread(() -> {
            LockSupport.unpark(t1);
            LockSupport.unpark(t1);
            System.out.println(Thread.currentThread().getName() + " 发起通知！");
        }, "t2").start();
        t1.start();
    }
}